# ----------------------------------------------------------------------------
#       Copyright (C) 2013-2014 Huynh Vi Lam  <domovilam@gmail.com>
#
#       This file is part of pimucha.
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------



# ----------------------------------------------------------------------------
# Use to send and receive X10 raw data over powerline from CM11a interface
# Python version 2.7.x and 3.x
# ----------------------------------------------------------------------------
# Software HEYU
# -------------
# - Website: http://www.heyu.org
# - HEYU is used as base for development of scripts
# ----------------------------------------------------------------------------


import logging,time
from .devcomm.devserial import DEVserial
from .ctrlfcts.cm11fct import (ackpwfail,requestcmd,testwrite)

logger = logging.getLogger()


class CM11(DEVserial):
    def __init__(self,port=None):
        DEVserial.__init__(self,port)
        self.idcontroller = 'CM11'
        self.port = port
        self._baudrate = 4800
        self.setup = False
        self.TXcap = True
        self.RXcap = True
 
    def tsetup(self):
        """
        Setup interface with
           Ack powerfail signal
           Request Status
	"""
        self.open()
        if not self.opened:
            return
        logger.debug("%s Starting with tests....",self.idcontroller)
        data = self.waitread()
        if not self.testread(data):
            if testwrite(self):
                logger.debug("Success of test write House Code A")
            else:
                logger.error("No response from controller to test write House Code A")
                self.opened = False
        if self.opened:
            logger.warning("%s Ready....",self.idcontroller)
            self.setup = True
            self.device = self.idcontroller + '-' + self.port

    def testread(self,data):
        logger.debug("Test reading data %s....",repr(data))
        if data is None:
            return False
        elif data == 0xA5:
            if not ackpwfail(self):
                logger.critical("Unable to ack Powerfail Signal %s",self.idcontroller)
                return False
        elif data == 0x5A:
            evt = self.cm11RI()
            logger.debug("RI: An event is incoming %s",repr(evt))
        return True

    def waitread(self):
        logger.debug("%s waiting for reading data....",self.idcontroller)
        n = 0
        while n < 5:
            data = self.read()
            if data:
                return data
            time.sleep(0.1)
            n += 1
        return None

    def chkwrite(self,byte1,byte2):
        n = 0
        checksum = int(byte1,16) + int(byte2,16)
        logger.debug("%s %s checksum = %s",byte1,byte2,hex(checksum))
        chk = 0x00
        while n < 5:
            self.write(byte1)
            self.write(byte2)
            chk = self.read()
            if not self.testread(chk): return False
            if checksum == chk:
                return True
            n += 1
        return False

    def writeack(self,byte1,byte2):
        if self.chkwrite(byte1,byte2):
            self.write('0x00')
            ack = self.waitread()
            if not self.testread(ack): return False
            if ack == 0x55:
                return True
        return False

    def request(self,rcmd):
        return requestcmd(self,rcmd)

    def cm11data(self,nb):
        """
        Receive data over powerline
        """
        if not nb : return None
        data = ["0x%02x" % nb]
        if nb < 10:			#CM11a Interface buffer max length
            while True:
                res = self.readh()
                if res:
                     data.append(res)
                     if len(data) == nb + 1:
                        break
        else:
           logger.warning("Value read %s for the buffer, greater than max size (10) for incoming data omitting this read", nb)
           data = None
        return data
       
    def cm11RI(self):
        """
        One loop until CM11 incoming signal 0x5a
        """
        logger.debug("Function cm11RI")
        RI = 0x5A
        data = None
        while RI == 0x5A:
            self.write('0xC3')	#PC Response to the Poll Signal
            data = self.read()
            if (data == None) or (data == 0x5A) or (data == 0xC3):
                pass
            else:
                break
        return self.cm11data(data)

    def cm11evt(self):
        """
        Receiving one partial event over powerline
        Return an sequence of hex string (bytes)
        """
        evt = None
        data = self.read()
        if data == 0x5A:
             evt = self.cm11RI()
        return evt

    def cm11complete(self):
        """
        Receiving an complete X10 event (2 partial events) over powerline
        Return an sequence of hex string (bytes)
        """
        events = None
        event = self.cm11evt()
        if event:
            while True:
                nextevt = self.cm11evt()
                if nextevt:
                    if (event[1] == '0x00') and (nextevt[1] == '0x01') :
                        events = " ".join(event + nextevt)
        return events

    def plsend(self,args,msgq=None,retries=3):
        """
        Sending a command over powerline with header hd if exist
        hu house unit 0x66 = A1
        hf house function 0x64 = A DIM
        hd header byte for DIM/BRIGHT function and amount DIM
        The send command is asynchronous
            False will return immediatly
            True will return after 0.5s
        args = hex string
        """
        logger.debug("Function plsend with CM11")
        hu,hf,hd = args.split()
        ack = None
        if self.writeack('0x04',hu):	#Send house + unit code
            if hd == '0x00':		#Send house + function (ON|OFF) code
                ack = self.writeack('0x06',hf)
            else:			#Send a house + function (DIM/BRIGHT) code
                ack = self.writeack(hd,hf)
            if ack:
                logger.debug("Successfuly send %s to controller CM11", repr(args))
                if msgq : msgq.put_nowait([self.idcontroller,'PL',args,'Success'])
                return                
        logger.error("Unable to send %s to controller CM11",repr(args))
        if msgq : msgq.put_nowait([self.idcontroller,'PL',args,'Fail'])

    def rfsend(self):
        return None

    def rxevent(self):
        """
        Receiving one partial event over powerline
        Return an string
        """
        event = None
        data = self.read()
        if data == 0x5A:
             event = self.cm11RI()
        else:
             return None
        return " ".join(event)

